package cn.tedu.jdbc.dao;

import cn.tedu.jdbc.utils.DbUtils;

import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * BaseDao是最基础的Dao，所有的Dao都继承这个类
 */
public class BaseDao {
    /**
     * 这是一个通用的执行insert delete  update语句的方法。
     * @param sql
     * @param params
     * @return
     */
    public int executeUpdate(String sql, Object... params) {
        //声明变量
        Connection conn = null;
        PreparedStatement ps = null;
        int count = 0;
        try {
            //获取链接
            conn = DbUtils.getConnection();
            //获取预编译的数据库操作对象
            ps = conn.prepareStatement(sql);
            //给 ？ 占位符传值
            if (params != null && params.length>0){
                //判断是否有占位符 ？
                for (int i = 0;i<params.length;i++){
                    ps.setObject(i+1,params[i]);
                }
            }
            //执行SQL语句，获取结果集
            count = ps.executeUpdate();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            DbUtils.close(conn,ps, null);
        }
        //返回结果
        return  count;
    }


    public <T> List<T> executeQuery(Class<T> clazz, String sql,Object... params){
        //声明变量
        List<T> list = new ArrayList<>();
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            //获取连接
            conn = DbUtils.getConnection();
            //获取预编译的数据库操作对象
            ps = conn.prepareStatement(sql);
            //给 ？ 占位符传值
            if (params != null && params.length>0){
                for (int i = 0;i<params.length;i++){
                    ps.setObject(i+1,params[i]);
                }
            }
            //执行SQL语句，获取结果集
            rs = ps.executeQuery();
             //获取结果集的元数据
            ResultSetMetaData rsmd = rs.getMetaData();

            //获取列数
            int columnCount = rsmd.getColumnCount();

            //处理查询结果集
            while (rs.next()){
                //封装Bean对象
                T obj = clazz.newInstance();
                //给Bean对象属性赋值
                /*
                * 举例子：比如现在有一张表；表名为：t_user，然后表中有两个字段，一个是 user_id,一个是 user_name
                * 现在javabean是User类，该类中的属性名是：userId，userName
                * 执行这样的SQL语句：select user_id as userId，user_name as userName from t_user；
                * as指的是 列的别名，将列的别名作为属性名，将列的值作为属性值
                * */
                for (int i = 1; i <= columnCount; i++){
                    //获取查询结果集中的列的名字
                    //这个列的名字是通过as关键字进行了起别名，这个列名就是bean的属性名。
                    String fieldName = rsmd.getColumnLabel(i);
                    //获取属性Field对象
                    Field declaredField = clazz.getDeclaredField(fieldName);
                    //打破封装
                    declaredField.setAccessible(true);
                    //给属性赋值
                    declaredField.set(obj, rs.getObject(i));
                }
                //将对象添加到List集合
                list.add(obj);
            }
            //返回List集合
        } catch (SQLException | InstantiationException | IllegalAccessException | NoSuchFieldException e) {
            throw new RuntimeException(e);
        } finally {
            DbUtils.close(conn,ps,rs);
        }
        return list;
    }


}
